﻿using FlyIL.Expression;

namespace FlyIL.Trace;



public class ExpByTrace : Expr
{


    public ExpByTrace(object a, Opt opt, object b) : base(a, opt, b)
    {

    }

    public ExpByTrace(object a) : base(a) { }


    /// <summary>
    /// 目标操作数 是否有被消费
    /// </summary>
    public bool HasTargetBeenUsed { get; internal set; }

    /// <summary>
    /// 目标操作数 是否有被更改
    /// </summary>
    public bool HasTargetBeenChanged { get; internal set; }


    /// <summary>
    /// 追踪到的中间数 有否被修改 
    /// </summary>
    public bool HasFactorBeenChanged { get; internal set; }


    /// <summary>
    /// 是否有效
    /// </summary>
    public bool IsValid
    {
        get
        {
            if (this.Calculable)
                return true;

            return !HasFactorBeenChanged;
        }
    }
}

public static partial class Tracer
{





    /// <summary>
    /// 严格追踪!!!
    /// 去掉递归设计 , 这里是核心逻辑 ，同 TraceUp 使用同一结构
    /// 同时确保 表达式的原子性 
    /// </summary>
    /// <param name="from">追踪节点，<para>同时用来判断是否被消费,所以必须是op 所在的节点</para></param>
    /// <param name="op">要追踪的操作数</param>
    public static ExpByTrace TraceStrict(this Context vcontext, Inst from, ref Operand op, Inst stop = null)
    {
        TraceCore traceExp = new(vcontext, from, op)
        {
            CheckFactor = true
        };

        var main = traceExp.Trace(stop);

        /********************
         * 检测有没有 无效的栈变量  [esp -4] 
         * *********************/
        if (main != null)
            if (main.Find<Operand?>(o => (bool)(o?.IsStackValue) && ((int)(o?.u32) < 0)) is not null)
                return null;


        if (main is not null)
            main.HasFactorBeenChanged = vcontext.HasFactorBeenChanged(main, from, op);

        return main;
    }

    /// <summary>
    /// 弱追踪， 对表达式不进行校验，!!! 慎用
    /// </summary>
    /// <param name="from">追踪节点，<para>同时用来判断是否被消费,所以必须是op 所在的节点</para></param>
    /// <param name="op">要追踪的操作数</param>
    public static ExpByTrace TraceWeak(this Context vcontext, Inst from, ref Operand op, Inst stop = null)
    {
        TraceCore traceExp = new(vcontext, from, op);
        return traceExp.Trace(stop);
    }

    public static ExpByTrace TraceExp(this Context vcontext, Inst from, Expr exp, Inst stop = null)
    {
        TraceCore traceExp = new(vcontext, from, exp);
        /// 之里仅仅是 最原始的  表达式 ， 需要修饰和调整 
        return traceExp.Trace(stop);
    }

}
